/*
 * Copyright (C) 2006 Claus Wahlers and Max Herkender
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

package com.common.zip.fzip
{
	import com.common.zip.utils.ChecksumUtil;

	import flash.utils.*;

	/**
	 * Represents a file contained in a ZIP archive.
	 */
	public class CFZipFile extends FZipFile
	{
		// compression methods
		/**
		 * @private
		 */
		public static const COMPRESSION_NONE:int=0;
		/**
		 * @private
		 */
		public static const COMPRESSION_SHRUNK:int=1;
		/**
		 * @private
		 */
		public static const COMPRESSION_REDUCED_1:int=2;
		/**
		 * @private
		 */
		public static const COMPRESSION_REDUCED_2:int=3;
		/**
		 * @private
		 */
		public static const COMPRESSION_REDUCED_3:int=4;
		/**
		 * @private
		 */
		public static const COMPRESSION_REDUCED_4:int=5;
		/**
		 * @private
		 */
		public static const COMPRESSION_IMPLODED:int=6;
		/**
		 * @private
		 */
		public static const COMPRESSION_TOKENIZED:int=7;
		/**
		 * @private
		 */
		public static const COMPRESSION_DEFLATED:int=8;
		/**
		 * @private
		 */
		public static const COMPRESSION_DEFLATED_EXT:int=9;
		/**
		 * @private
		 */
		public static const COMPRESSION_IMPLODED_PKWARE:int=10;

		/**
		 * @private
		 */
		protected static var HAS_UNCOMPRESS:Boolean=(describeType(ByteArray).factory.method.(@name == "uncompress").parameter.length() > 0);
		/**
		 * @private
		 */
		protected static var HAS_INFLATE:Boolean=(describeType(ByteArray).factory.method.(@name == "inflate").length() > 0);

		/**
		 * Constructor
		 */
		public function CFZipFile(filenameEncoding:String="utf-8")
		{
		}
		/**
		 * @private
		 */
		override protected function parseHead(data:IDataInput):void
		{
			var vSrc:uint=data.readUnsignedShort();
			_versionHost=vSrc >> 8;
			_versionNumber=Math.floor((vSrc & 0xff) / 10) + "." + ((vSrc & 0xff) % 10);
			var flag:uint=data.readUnsignedShort();
			_compressionMethod=data.readUnsignedShort();
			_encrypted=(flag & 0x01) !== 0;
			_hasDataDescriptor=(flag & 0x08) !== 0;
			_hasCompressedPatchedData=(flag & 0x20) !== 0;
			if ((flag & 800) !== 0)
			{
				_filenameEncoding="utf-8";
			}
			if (_compressionMethod === COMPRESSION_IMPLODED)
			{
				_implodeDictSize=(flag & 0x02) !== 0 ? 8192 : 4096;
				_implodeShannonFanoTrees=(flag & 0x04) !== 0 ? 3 : 2;
			}
			else if (_compressionMethod === COMPRESSION_DEFLATED)
			{
				_deflateSpeedOption=(flag & 0x06) >> 1;
			}
			var msdosTime:uint=data.readUnsignedShort();
			var msdosDate:uint=data.readUnsignedShort();
			var sec:int=(msdosTime & 0x001f);
			var min:int=(msdosTime & 0x07e0) >> 5;
			var hour:int=(msdosTime & 0xf800) >> 11;
			var day:int=(msdosDate & 0x001f);
			var month:int=(msdosDate & 0x01e0) >> 5;
			var year:int=((msdosDate & 0xfe00) >> 9) + 1980;
			_date=new Date(year, month - 1, day, hour, min, sec, 0);
			_crc32=data.readUnsignedInt();
			_sizeCompressed=data.readUnsignedInt();
			_sizeUncompressed=data.readUnsignedInt();
			_sizeFilename=data.readUnsignedShort();
			_sizeExtra=data.readUnsignedShort();
		}
		/**
		 * @private
		 */
		override protected function parseFileHead(stream:IDataInput):Boolean
		{
			if (stream.bytesAvailable >= 30)
			{
				parseHead(stream);
				if (_sizeFilename + _sizeExtra > 0)
				{
					parseFunc=parseFileHeadExt;
				}
				else
				{
					parseFunc=parseFileContent;
				}
				return true;
			}
			return false;
		}
	}
}
